package com.oba.base.dao;

import java.io.Serializable;
import java.sql.SQLException;
import java.util.Collection;
import java.util.Date;
import java.util.List;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.DetachedCriteria;
import org.springframework.orm.hibernate3.HibernateCallback;

import com.oba.base.interfaces.IBaseBo;
import com.oba.base.interfaces.IHsqlBuilder;
import com.oba.base.util.Util;
import com.oba.king.login.UserInfo;
import com.oba.king.sysmanager.log.Log;
import com.oba.king.sysmanager.log.LogBean;
import com.oba.king.sysmanager.log.TableInfo;
import com.oba.king.sysmanager.log.TableService;

/**
 * 所有的Dao都要继承BaseDao,所有的数据库操作均调用本类的方法实现， 本类中的jdao为JDBC Dao，需要使用JDBC操作时可调用此类的方法
 * 
 * @author han
 * 
 */
public class BaseDao {
	private HibernateDaoSupportImpl hdao;
	protected JdbcDao jdao;

	public void setHdao(HibernateDaoSupportImpl hdao) {
		this.hdao = hdao;
	}

	public void setJdao(JdbcDao jdao) {
		this.jdao = jdao;
	}

	protected List findByCriteria(DetachedCriteria criteria) {
		return hdao.getHibernateTemplate().findByCriteria(criteria);
	}
	
	/**
	 * 记录日志
	 */
	public void saveLog(IBaseBo bo,int type) {
		TableService ts = TableService.getInit();
		Integer code = bo.getClass().toString().hashCode();
		TableInfo ti = ts.getTableInfo(code);
		if(ti != null) {
			Log log = new Log();
			log.setNewBo(true);
			log.setCode(code);
			log.setItemId(bo.getId());
			log.setSaveTime(new Date());
			log.setType(type);
			UserInfo user = ((LogBean)Util.getBean("logBean")).getSysUser();
			System.out.println("--------------"+user.getAccount());
			log.setUserInfo(user);
			hdao.getHibernateTemplate().save(log);
		}
	}

	/**
	 * IBaseVo类型对象保存
	 * 
	 * @param obj
	 *            被保存对象
	 */
	public void save(IBaseBo bo) {
		if (bo.isNewBo()) {
			bo.setNewBo(false);
			hdao.getHibernateTemplate().save(bo);
			saveLog(bo,1);
		} else {
			hdao.getHibernateTemplate().update(bo);
			saveLog(bo,2);
		}
	}

	/**
	 * 
	 * 对象集合保存（可为非IBaseVo类型对象）
	 * 
	 * @param coll
	 *            被保存对象集合
	 */
	protected void save(Collection<?> collect) {
		hdao.getHibernateTemplate().saveOrUpdateAll(collect);
		for(Object obj : collect) {
			IBaseBo bo = (IBaseBo)obj;
			if(bo.isNewBo()) {
				saveLog(bo,1);
			}else {
				saveLog(bo,2);
			}
		}
	}

	/**
	 * 多个传入参数批量更新
	 * 
	 * @param queryString
	 *            更新HSQL
	 * @param values
	 *            多个传入的参数
	 */
	protected int bulkUpdate(String queryString, Object[] values) {
		return hdao.getHibernateTemplate().bulkUpdate(queryString, values);
	}

	/**
	 * IBaseBo类型对象数据库获取
	 * 
	 * @param tname
	 *            获取的对象所属类
	 * @param id
	 *            获取的对象ID
	 * @return 被获取的对象
	 */
	public <Tvo> Tvo load(Class<Tvo> tname, Serializable id) {
		return (Tvo) hdao.getHibernateTemplate().get(tname, id);
	}

	/**
	 * 数据库锁
	 */
	private static final byte[] DATABOLB_LOCK = new byte[0];

	/**
	 * IBaseVo类型对象的删除
	 * 
	 * @param <Tvo>
	 * @param obj
	 *            删除对象
	 */

	public void delete(IBaseBo bo) {
		if (!bo.isNewBo()) {
			saveLog(bo,3);
			hdao.getHibernateTemplate().delete(bo);
		}
	}

	/**
	 * 对象集合的删除
	 * 
	 * @param entities
	 *            删除的对象集合
	 */
	protected void deleteAll(Collection<? extends Object> entities) {
		for(Object obj : entities) {
			IBaseBo bo = (IBaseBo)obj;
			saveLog(bo,3);
		}
		hdao.getHibernateTemplate().deleteAll(entities);
	}

	public void deleteAssociate(Class<?> cls, String[] propNames,
			IBaseBo[] propValues) {
		for (int i = 0; i < propValues.length; i++) {
			if (propValues[i].isNewBo())
				return;
		}
		StringBuilder sb = new StringBuilder();
		sb.append("delete from ");
		sb.append(cls.getSimpleName());
		sb.append(getQueryAndTerm(propNames));
		bulkUpdate(sb.toString(), propValues);
	}

	private String getQueryAndTerm(String[] propNames) {
		if (propNames == null || propNames.length == 0)
			return "";
		StringBuilder sb = new StringBuilder(" where ");
		for (int i = 0; i < propNames.length; i++) {
			sb.append(propNames[i]);
			sb.append("=? and ");
		}
		return sb.substring(0, sb.length() - 5);
	}

	/**
	 * 按HSQL查询对象列表
	 * 
	 * @param hsql
	 *            HSQL语句串
	 * @return 查询的对象列表
	 */
	protected List find(String hsql) {
		return hdao.getHibernateTemplate().find(hsql);
	}

	/**
	 * 按HSQL查询对象列表
	 * 
	 * @param hsql
	 *            HSQL语句串
	 * @param value
	 *            传入的单个查询参数
	 * @return 查询的对象列表
	 */

	protected List find(String hsql, Object value) {
		return hdao.getHibernateTemplate().find(hsql, value);
	}

	/**
	 * 按HSQL查询对象列表
	 * 
	 * @param hsql
	 *            HSQL语句串
	 * @param values
	 *            传入的查询参数数组
	 * @return 查询的对象列表
	 */
	protected List find(String hsql, Object[] values) {
		return hdao.getHibernateTemplate().find(hsql, values);
	}
	
	/**
	 * 按HSQL分页查询对象列表
	 * 
	 * @param hql
	 *            HSQL 语句
	 * @param params
	 *            传入的参数数组
	 * @param firstResult
	 *            当前页第一条记录所处位置
	 * @param maxresult
	 *            每页的记录数
	 * @return 当前页的对象列表
	 */
	protected List find(final String hql, final Object[] params,
			final int firstResult, final int maxresult) {
		return hdao.getHibernateTemplate().executeFind(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				Query query = session.createQuery(hql);
				if (params != null) {
					for (int i = 0; i < params.length; i++)
						query.setParameter(i, params[i]);
				}
				query.setFirstResult(firstResult);
				query.setMaxResults(maxresult);
				List<?> list = query.list();
				return list;
			}

		});
	}

	/**
	 * 按HSQL分页查询对象列表
	 * 
	 * @param hql
	 *            HSQL 语句
	 * @param firstResult
	 *            当前页第一条记录所处位置
	 * @param maxresult
	 *            每页的记录数
	 * @return 当前页的对象列表
	 */
	protected List find(String hsql, int firstResult, int maxresult) {
		return find(hsql, null, firstResult, maxresult);
	}

	/**
	 * 按实例查询对象列表
	 * 
	 * @param examplEntity
	 *            参照样例对象
	 * @return 查询对象列表
	 */
	public List findByExample(Object examplEntity) {
		return hdao.getHibernateTemplate().findByExample(examplEntity);
	}

	/**
	 * 按实例分页查询对象列表
	 * 
	 * @param examplEntity
	 *            参照样例对象
	 * @param firstResult
	 *            当前页第一条记录所处位置
	 * @param maxresult
	 *            每页的记录数
	 * @return 查询对象列表
	 */
	public List findByExample(Object exampleEntity, int firstResult,
			int maxResults) {
		return hdao.getHibernateTemplate().findByExample(exampleEntity,
				firstResult, maxResults);
	}
	
	/**
	 * 
	 * 强制对代理实例化
	 */
	public void initialize(Object obj) {
		hdao.getHibernateTemplate().initialize(obj);
	}

	public List findAll(Class cls) {
		return find("from " + cls.getSimpleName());
	}

	public void evict(Object obj) {
		hdao.getHibernateTemplate().evict(obj);
	}
	
	/**
	 * 获取统计数量sql
	 */
	protected StringBuilder getCountSql(Object bo) {
		StringBuilder sb = new StringBuilder();
		sb.append("select count(*) from ");
		sb.append(bo.getClass().getSimpleName());
		return sb;
	}
	
	protected IHsqlBuilder getSqlBuilder(String sqlpre) {
		return HsqlBuilder.create(sqlpre, this);
	}

	protected IHsqlBuilder getSqlBuilder(String sql, Object[] params) {
		return HsqlBuilder.create(sql, params, this);
	}
	
	/**
	 * 判定对象是否唯一
	 */
	public boolean isUniqueBo(IBaseBo bo, String propName, Object propValue) {
		IHsqlBuilder sql = getCountSql(bo, propName, propValue);
		return isCountZero(sql);
	}

	/**
	 * 判定对象是否唯一
	 */
	public boolean isUniqueBo(IBaseBo bo, String[] propNames,
			Object[] propValues) {
		IHsqlBuilder sql = getCountSql(bo, propNames, propValues);
		return isCountZero(sql);
	}
	
	/**
	 * 获取统计数量sql
	 */
	protected IHsqlBuilder getCountSql(IBaseBo bo, String[] propNames,
			Object[] propValues) {
		IHsqlBuilder hsql = HsqlBuilder
				.create(getCountSql(bo).toString(), this);
		for (int i = 0; i < propNames.length; i++) {
			hsql.add(propNames[i] + "=?", propValues[i]);
		}
		hsql.add("id !=?", bo.getId());
		return hsql;
	}
	
	/**
	 * 获取统计数量sql
	 */
	protected IHsqlBuilder getCountSql(IBaseBo bo, String propName,
			Object propValue) {
		IHsqlBuilder hsql = HsqlBuilder
				.create(getCountSql(bo).toString(), this);
		hsql.add(propName + "=?", propValue);
		hsql.add("id !=?", bo.getId());
		return hsql;
	}
	
	/**
	 * 判定满足条件的记录数量是否等于零
	 */
	protected boolean isCountZero(IHsqlBuilder sql) {
		sql.build();
		Long rows = (Long) hdao.getHibernateTemplate().find(sql.getHsql(),
				sql.getValues()).get(0);
		return rows.intValue() == 0;
	}
	
	/**
	 * 用HSQL构建器分页查询对象列表
	 * 
	 * @param hsqlbuilder
	 *            HSQL构建器
	 * @param firstResult
	 *            当前页第一条记录所处位置
	 * @param maxresult
	 *            每页的记录数
	 * @return 当前页的对象列表
	 */
	protected List find(IHsqlBuilder hsqlbuilder, int firstResult, int maxresult) {
		hsqlbuilder.build();
		return find(hsqlbuilder.getHsql(), hsqlbuilder.getValues(),
				firstResult, maxresult);
	}
	
	/**
	 * 利用HSQL构建器查询对象列表
	 * 
	 * @param hsqlbuilder
	 *            HSQL构建器
	 * @return 查询的对象列表
	 */
	protected List find(IHsqlBuilder hsqlbuilder) {
		hsqlbuilder.build();
		return find(hsqlbuilder.getHsql(), hsqlbuilder.getValues());
	}
	
	public String getNextSerial(Class<? extends IBaseBo> cls,
			String serialProp, String parentSerial, Long serialLength) {
		StringBuilder sb = new StringBuilder("select max(");
		sb.append(serialProp);
		sb.append(") from ");
		sb.append(cls.getSimpleName());
		sb.append(" where ");
		sb.append(serialProp);
		sb.append(" like ? and length(");
		sb.append(serialProp);
		sb.append(")=?");
		List<String> lis = find(sb.toString(), new Object[] {
				parentSerial + "%", serialLength });
		String maxSerial = lis.get(0);
		int nextSerial;
		if (maxSerial == null) {
			nextSerial = 1;
		} else {
			nextSerial = Integer.parseInt(maxSerial.substring(parentSerial
					.length(), serialLength.intValue()));
			nextSerial++;
		}
		return parentSerial
				+ Util.numberFormat(nextSerial, serialLength.intValue()
						- parentSerial.length());
	}

	public String getNextSerial(Class<? extends IBaseBo> cls,
			String serialProp, String parentSerial) {
		return getNextSerial(cls, serialProp, parentSerial, new Long(
				parentSerial.length() + 2));
	}
	
}
